package com.project.common.domain.po;

import com.fasterxml.jackson.annotation.JsonIgnore;
import com.project.common.domain.DataScopeAware;
import io.swagger.v3.oas.annotations.media.Schema;
import javax.persistence.Column;
import javax.persistence.EntityListeners;
import javax.persistence.MappedSuperclass;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.hibernate.annotations.*;
import org.springframework.data.annotation.CreatedBy;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.annotation.LastModifiedBy;
import org.springframework.data.annotation.LastModifiedDate;
import org.springframework.data.domain.ExampleMatcher;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;

/**
 * 增加了jackson-datatype-hibernate5就不需要这个Ignore了
 * 公用业务继承类
 *
 */
@MappedSuperclass
@Data
@NoArgsConstructor
@AllArgsConstructor
@EntityListeners({DataScopeAware.class, AuditingEntityListener.class})
@FilterDefs({@FilterDef(name = "orgKeyFilter", parameters = @ParamDef(name = "orgKey", type = "java.lang.String"), defaultCondition = "org_key like :orgKey"),
        @FilterDef(name = "roleKeysFilter", parameters = @ParamDef(name = "roleKeys", type = "java.lang.String"), defaultCondition = "role_keys like :roleKeys"),
        @FilterDef(name = "roleKeysFilter2", parameters = @ParamDef(name = "roleKeys", type = "java.lang.String"),
                defaultCondition = "role_keys like :roleKey1 or role_keys like :roleKey2"),
        @FilterDef(name = "roleKeysFilter3", parameters = @ParamDef(name = "roleKeys", type = "java.lang.String"),
                defaultCondition = "role_keys like :roleKey1 or role_keys like :roleKey2 or role_keys like :roleKey3"),
        @FilterDef(name = "roleKeysFilter4", parameters = @ParamDef(name = "roleKeys", type = "java.lang.String"),
                defaultCondition = "role_keys like :roleKey1 or role_keys like :roleKey2 or role_keys like :roleKey3 or role_keys like :roleKey4"),
        @FilterDef(name = "roleKeysFilter5", parameters = @ParamDef(name = "roleKeys", type = "java.lang.String"),
                defaultCondition = "role_keys like :roleKey1 or role_keys like :roleKey2 or role_keys like :roleKey3 or role_keys like :roleKey4 or role_keys like :roleKey5"),
        @FilterDef(name = "createByFilter", parameters = @ParamDef(name = "createBy", type = "java.lang.Long"), defaultCondition = "create_by = :createBy")})

@Filters({@Filter(name = "orgKeyFilter"),
        @Filter(name = "roleKeysFilter"),
        @Filter(name = "roleKeysFilter2"),
        @Filter(name = "roleKeysFilter3"),
        @Filter(name = "roleKeysFilter4"),
        @Filter(name = "roleKeysFilter5"),
        @Filter(name = "createByFilter")})
public class BasePO extends BaseAutoKeyPO {
    @Schema(description = "组织编码")
    @Column(columnDefinition = "varchar(100) DEFAULT NULL COMMENT '组织编码'")
    @JsonIgnore
    private String orgKey;

    @Schema(description = "岗位角色编码")
    @Column(columnDefinition = "varchar(100) DEFAULT NULL COMMENT '岗位角色编码（多个,号分割）'")
    @JsonIgnore
    private String roleKeys;

    @Schema(description = "创建人")
    @CreatedBy
    @Column(name = "create_by", updatable = false)
    private Long createBy;

    @Schema(description = "创建时间")
    @Column(name = "create_time", updatable = false)
    @CreatedDate
    private LocalDateTime createTime;

    @Schema(description = "更新时间")
    @JsonIgnore
    @LastModifiedDate
    @Column(name = "update_time")
    private LocalDateTime updateTime;

    @Schema(description = "更新人")
    @JsonIgnore
    @CreatedBy
    @LastModifiedBy
    @Column(name = "update_by")
    private Long updateBy;

    public static ExampleMatcher build() {
        //创建匹配器，即如何使用查询条件
        ExampleMatcher exampleMatcher = ExampleMatcher
                //采用默认and的查询方式
                .matchingAll()
                //忽略大小写
                .withIgnoreCase()
                //忽略所有null值的字段
                .withIgnoreNullValues()
                //.withIgnorePaths("id","createDate")
                //默认采用精准匹配规则
                .withStringMatcher(ExampleMatcher.StringMatcher.EXACT)
                //特殊指定roleKeys字段采用前缀匹配规则 todo
                .withMatcher("roleKeys", ExampleMatcher.GenericPropertyMatchers.startsWith())
                //.withMatcher("roleKeys", ExampleMatcher.GenericPropertyMatchers.endsWith())
                //特殊指定orgKey字段采用前缀匹配规则
                //.withMatcher("orgKey", ExampleMatcher.GenericPropertyMatchers.endsWith());
                .withMatcher("orgKey", ExampleMatcher.GenericPropertyMatchers.startsWith());
        return exampleMatcher;
    }

    public static Specification dateScopeSpec() {
        return new BasePO().dateScopeCriteriaBuilder();
    }

    public static Predicate dateScopePredicate(Root root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
        return new BasePO().dateScopeCriteriaBuilder(root, criteriaQuery, criteriaBuilder);
    }

    public Specification dateScopeCriteriaBuilder() {
        return (root, criteriaQuery, criteriaBuilder) -> this.dateScopeCriteriaBuilder(root, criteriaQuery, criteriaBuilder);
    }

    public Predicate dateScopeCriteriaBuilder(Root root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
        criteriaQuery.distinct(true);
        List<Predicate> predicates = new ArrayList<>();
        predicates.add(criteriaBuilder.equal(root.get("isDelete"), 0));
        //部门及以下
        if (StringUtils.isNotBlank(this.getOrgKey())) {
            predicates.add(criteriaBuilder.like(root.get("orgKey"), this.getOrgKey() + "%"));
        }
        //岗位及以下
        if (StringUtils.isNotBlank(this.getRoleKeys())) {
            String[] roleKeys = this.getRoleKeys().split(",");
            if (roleKeys.length > 0) {
                Predicate[] keys = new Predicate[roleKeys.length];
                for (int i = 0; i < roleKeys.length; i++) {
                    if (StringUtils.isNotBlank(roleKeys[i])) {
                        keys[i] = criteriaBuilder.like(root.get("roleKeys"), '%'+ roleKeys[i] + '%');
                    }
                }
                predicates.add(criteriaBuilder.or(keys));
            }
        }
        //本人的数据
        if (this.getCreateBy() != null) {
            predicates.add(criteriaBuilder.equal(root.get("createBy"), this.getCreateBy()));
        }
        Predicate[] predicateArray = new Predicate[predicates.size()];
        return criteriaBuilder.and(predicates.toArray(predicateArray));
    }
}